using Crux.Core.Dapper.SqlGenerator;

namespace Crux.Core.Dapper;

/// <summary>
/// 
/// </summary>
/// <typeparam name="TContext"></typeparam>
public interface IUnitOfWork<out TContext>
    : IDisposableObservable, IAsyncDisposableObservable
    where TContext : DapperContext
{
    /// <summary>
    ///
    /// </summary>
    TContext Context { get; }

    /// <summary>
    ///
    /// </summary>
    IDbTransaction? Transaction { get; }

    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    IDbTransaction BeginTransaction();

    /// <summary>
    ///
    /// </summary>
    /// <param name="isolationLevel"></param>
    /// <returns></returns>
    IDbTransaction BeginTransaction(IsolationLevel isolationLevel);

    /// <summary>
    ///
    /// </summary>
    /// <param name="timeout"></param>
    /// <returns></returns>
    IUnitOfWork<TContext> SetTimeout(in int timeout);

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="configure"></param>
    TEntity Add<TEntity>(TEntity entity, Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<TEntity> AddAsync<TEntity>(TEntity entity, Action<SqlGenerator<TEntity>>? configure = null, CancellationToken cancellationToken = default)
        where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="configure"></param>
    int AddRange<TEntity>(IEnumerable<TEntity> entities, Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> AddRangeAsync<TEntity>(IEnumerable<TEntity> entities, Action<SqlGenerator<TEntity>>? configure = null, CancellationToken cancellationToken = default)
        where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    TEntity Update<TEntity>(TEntity entity, Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<TEntity> UpdateAsync<TEntity>(
        TEntity entity,
        Action<SqlGenerator<TEntity>>? configure = null,
        CancellationToken cancellationToken = default) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="where"></param>
    /// <param name="expression"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    int Update<TEntity>(
        Expression<Func<TEntity, bool>> where,
        Expression<Func<TEntity, TEntity>> expression,
        Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="where"></param>
    /// <param name="expression"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> UpdateAsync<TEntity>(
        Expression<Func<TEntity, bool>> where,
        Expression<Func<TEntity, TEntity>> expression,
        Action<SqlGenerator<TEntity>>? configure = null,
        CancellationToken cancellationToken = default) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    int UpdateRange<TEntity>(
        IEnumerable<TEntity> entities,
        Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> UpdateRangeAsync<TEntity>(
        IEnumerable<TEntity> entities,
        Action<SqlGenerator<TEntity>>? configure = null,
        CancellationToken cancellationToken = default) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    TEntity Delete<TEntity>(TEntity entity,
        Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    TEntity PhysicsDelete<TEntity>(TEntity entity,
        Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="where"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    int Delete<TEntity>(Expression<Func<TEntity, bool>> where,
        Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="where"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    int PhysicsDelete<TEntity>(Expression<Func<TEntity, bool>> where,
        Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    int DeleteRange<TEntity>(IEnumerable<TEntity> entities,
        Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    int PhysicsDeleteRange<TEntity>(IEnumerable<TEntity> entities,
        Action<SqlGenerator<TEntity>>? configure = null) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<TEntity> DeleteAsync<TEntity>(TEntity entity,
        Action<SqlGenerator<TEntity>>? configure = null, CancellationToken cancellationToken = default)
        where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<TEntity> PhysicsDeleteAsync<TEntity>(TEntity entity,
        Action<SqlGenerator<TEntity>>? configure = null, CancellationToken cancellationToken = default)
        where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="where"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> DeleteAsync<TEntity>(Expression<Func<TEntity, bool>> where,
        Action<SqlGenerator<TEntity>>? configure = null, CancellationToken cancellationToken = default)
        where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="where"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> PhysicsDeleteAsync<TEntity>(Expression<Func<TEntity, bool>> where,
        Action<SqlGenerator<TEntity>>? configure = null,
        CancellationToken cancellationToken = default) where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> DeleteRangeAsync<TEntity>(IEnumerable<TEntity> entities,
        Action<SqlGenerator<TEntity>>? configure = null, CancellationToken cancellationToken = default)
        where TEntity : class;

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="configure"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> PhysicsDeleteRangeAsync<TEntity>(IEnumerable<TEntity> entities,
        Action<SqlGenerator<TEntity>>? configure = null,
        CancellationToken cancellationToken = default) where TEntity : class;
}